/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.test;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.web.bindery.event.shared.UmbrellaException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Evgen Vidolob
*/
public class GwtReflectionUtils {
public static void callOnFailure(AsyncRequestCallback<?> callback, Object... args){
callPrivateMethod(callback, "onFailure", args);
}
public static void callOnSuccess(AsyncRequestCallback<?> callback, Object... args){
callPrivateMethod(callback, "onSuccess", args);
}
public static <T> T callPrivateMethod(Object target, String methodName, Object... args) {
if (target instanceof JavaScriptObject) {
throw new UnsupportedOperationException(
"Cannot call instance method on Overlay types without specifying its base type");
}
Method method = findMethod(target.getClass(), methodName, args);
if (method == null) {
throw new RuntimeException("Cannot find method '" + target.getClass().getName() + "."
+ methodName + "(..)'");
}
return (T) callPrivateMethod(target, method, args);
}
private static Method findMethod(Class<?> clazz, String methodName, Object... args) {
Class<?>[] l = new Class[args.length];
for (int i = 0; i < args.length; i++) {
l[i] = args[i] != null ? args[i].getClass() : null;
}
return findMethod(clazz, methodName, l);
}
public static Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
Class<?> searchType = clazz;
while (!Object.class.equals(searchType) && searchType != null) {
Method[] methods = searchType.isInterface() ? searchType.getMethods()
: searchType.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (name.equals(method.getName())
&& paramTypes.length == method.getParameterTypes().length) {
boolean compatibleParams = true;
for (int j = 0; j < paramTypes.length; j++) {
if (paramTypes[j] == null) {
// null class is a wildcard
continue;
}
Class<?> methodParamType = getCheckedClass(method.getParameterTypes()[j]);
Class<?> searchParamType = getCheckedClass(paramTypes[j]);
if (!methodParamType.isAssignableFrom(searchParamType)) {
compatibleParams = false;
}
}
if (compatibleParams) {
return method;
}
}
}
searchType = searchType.getSuperclass();
}
return null;
}
private static Class<?> getCheckedClass(Class<?> potentialPrimitiveType) {
if (!potentialPrimitiveType.isPrimitive()) {
return potentialPrimitiveType;
}
if (potentialPrimitiveType == Byte.TYPE) {
return Byte.class;
} else if (potentialPrimitiveType == Short.TYPE) {
return Short.class;
} else if (potentialPrimitiveType == Integer.TYPE) {
return Integer.class;
} else if (potentialPrimitiveType == Long.TYPE) {
return Long.class;
} else if (potentialPrimitiveType == Float.TYPE) {
return Float.class;
} else if (potentialPrimitiveType == Double.TYPE) {
return Double.class;
} else if (potentialPrimitiveType == Boolean.TYPE) {
return Boolean.class;
} else {
return Character.class;
}
}
public static <T> T callPrivateMethod(Object target, Method method, Object... args) {
try {
method.setAccessible(true);
Object res = method.invoke(target, args);
return (T) res;
} catch (InvocationTargetException e) {
if (AssertionError.class.isInstance(e.getCause())) {
throw (AssertionError) e.getCause();
} else if (UmbrellaException.class.isInstance(e.getCause())) {
throw new RuntimeException("Error while calling method '" + method.toString() + "'",
e.getCause().getCause());
}
throw new RuntimeException("Error while calling method '" + method.toString() + "'",
e.getCause());
} catch (Exception e) {
throw new RuntimeException("Unable to call method '"
+ target.getClass().getSimpleName() + "." + method.getName() + "(..)'", e);
}
}
}